import pygame
import random
import sys
from pygame.locals import *

# 初始化pygame
pygame.init()

# 游戏常量
WIDTH, HEIGHT = 600, 600
GRID_SIZE = 30
GRID_WIDTH = 16
GRID_HEIGHT = 16
MINES = 40
MARGIN = 50
TOP_MARGIN = 50

# 颜色定义
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY = (200, 200, 200)
DARK_GRAY = (150, 150, 150)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
GREEN = (0, 128, 0)
DARK_RED = (128, 0, 0)
PURPLE = (128, 0, 128)
MAROON = (128, 0, 0)
TURQUOISE = (64, 224, 208)
BLACK_COL = (0, 0, 0)
DARK_GRAY_COL = (100, 100, 100)
LIGHT_RED = (255, 200, 200)  # 用于错误标记

# 数字颜色
NUMBER_COLORS = {
    1: BLUE,
    2: GREEN,
    3: RED,
    4: PURPLE,
    5: MAROON,
    6: TURQUOISE,
    7: BLACK_COL,
    8: DARK_GRAY_COL
}

# 设置窗口
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('扫雷游戏')

# 尝试加载中文字体
try:
    font = pygame.font.SysFont('Microsoft YaHei', 30)
    small_font = pygame.font.SysFont('Microsoft YaHei', 20)
except:
    try:
        font = pygame.font.SysFont('SimHei', 30)
        small_font = pygame.font.SysFont('SimHei', 20)
    except:
        font = pygame.font.Font(None, 30)
        small_font = pygame.font.Font(None, 20)


class Cell:
    def __init__(self):
        self.is_mine = False
        self.is_revealed = False
        self.is_flagged = False
        self.neighbor_mines = 0
        self.correctly_flagged = False  # 追踪是否正确标记


class Board:
    def __init__(self, width, height, mines):
        self.width = width
        self.height = height
        self.mines = mines
        self.cells = [[Cell() for _ in range(height)] for _ in range(width)]
        self.first_click = True
        self.game_over = False
        self.win = False
        self.mines_flagged = 0

        # 初始化空板
        for x in range(width):
            for y in range(height):
                cell = self.cells[x][y]
                cell.is_mine = False
                cell.is_revealed = False
                cell.is_flagged = False
                cell.neighbor_mines = 0
                cell.correctly_flagged = False

    def place_mines(self, first_x, first_y):
        # 确保第一次点击不是地雷
        safe_cells = []
        for dx in range(-1, 2):
            for dy in range(-1, 2):
                nx, ny = first_x + dx, first_y + dy
                if 0 <= nx < self.width and 0 <= ny < self.height:
                    safe_cells.append((nx, ny))

        # 随机放置地雷
        mines_placed = 0
        while mines_placed < self.mines:
            x = random.randint(0, self.width - 1)
            y = random.randint(0, self.height - 1)
            if (x, y) not in safe_cells and not self.cells[x][y].is_mine:
                self.cells[x][y].is_mine = True
                mines_placed += 1

                # 更新邻居的地雷数量
                for dx in range(-1, 2):
                    for dy in range(-1, 2):
                        nx, ny = x + dx, y + dy
                        if 0 <= nx < self.width and 0 <= ny < self.height:
                            self.cells[nx][ny].neighbor_mines += 1

    def reveal(self, x, y):
        cell = self.cells[x][y]

        if cell.is_revealed or cell.is_flagged or self.game_over or self.win:
            return False

        if self.first_click:
            self.place_mines(x, y)
            self.first_click = False

        cell.is_revealed = True

        if cell.is_mine:
            self.game_over = True
            # 游戏失败后揭示所有地雷位置
            self.reveal_all_mines()
            return True

        # 如果周围没有地雷，自动揭示周围
        if cell.neighbor_mines == 0:
            self.reveal_neighbors(x, y)

        self.check_win()
        return True

    def reveal_all_mines(self):
        """揭示所有地雷位置"""
        for x in range(self.width):
            for y in range(self.height):
                cell = self.cells[x][y]
                if cell.is_mine and not cell.is_flagged:
                    # 揭示未被标记的地雷
                    cell.is_revealed = True
                elif cell.is_flagged and not cell.is_mine:
                    # 标记错误位置显示错误标志
                    cell.is_revealed = True
                elif cell.is_flagged and cell.is_mine:
                    # 正确标记的地雷
                    cell.correctly_flagged = True

    def reveal_neighbors(self, x, y):
        for dx in range(-1, 2):
            for dy in range(-1, 2):
                nx, ny = x + dx, y + dy
                if 0 <= nx < self.width and 0 <= ny < self.height:
                    if not self.cells[nx][ny].is_revealed and not self.cells[nx][ny].is_flagged:
                        self.cells[nx][ny].is_revealed = True
                        if self.cells[nx][ny].neighbor_mines == 0:
                            self.reveal_neighbors(nx, ny)

    def toggle_flag(self, x, y):
        cell = self.cells[x][y]
        if not cell.is_revealed and not self.game_over and not self.win:
            cell.is_flagged = not cell.is_flagged
            self.mines_flagged += 1 if cell.is_flagged else -1
            self.check_win()
            return True
        return False

    def check_win(self):
        for x in range(self.width):
            for y in range(self.height):
                cell = self.cells[x][y]
                if not cell.is_mine and not cell.is_revealed:
                    return
                if cell.is_mine and not cell.is_flagged:
                    return
        self.win = True

    def reveal_all(self):
        for x in range(self.width):
            for y in range(self.height):
                cell = self.cells[x][y]
                if not cell.is_revealed:
                    cell.is_revealed = True


def draw_board(board):
    # 清空屏幕
    screen.fill((230, 230, 230))

    # 计算网格区域的位置
    grid_area_width = GRID_WIDTH * GRID_SIZE
    grid_area_height = GRID_HEIGHT * GRID_SIZE

    # 信息区域高度和位置
    info_height = 40
    grid_top = TOP_MARGIN + info_height + 10

    # 绘制旗帜计数
    flags_text = font.render(f"旗帜: {board.mines_flagged}/{board.mines}", True, BLACK)
    flags_rect = pygame.Rect(20, TOP_MARGIN, flags_text.get_width() + 20, info_height)
    pygame.draw.rect(screen, GRAY, flags_rect)
    pygame.draw.rect(screen, DARK_GRAY, flags_rect, 2)
    screen.blit(flags_text, (flags_rect.x + 10, flags_rect.centery - flags_text.get_height() // 2))

    # 绘制状态信息
    status_text = ""
    status_color = BLACK
    if board.game_over:
        status_text = "游戏结束!"
        status_color = RED
    elif board.win:
        status_text = "恭喜获胜!"
        status_color = GREEN
    else:
        status_text = "游戏进行中"

    status_render = font.render(status_text, True, status_color)
    status_rect = pygame.Rect(WIDTH - status_render.get_width() - 40, TOP_MARGIN,
                              status_render.get_width() + 20, info_height)
    pygame.draw.rect(screen, GRAY, status_rect)
    pygame.draw.rect(screen, DARK_GRAY, status_rect, 2)
    screen.blit(status_render, (status_rect.x + 10, status_rect.centery - status_render.get_height() // 2))

    # 绘制重置按钮
    reset_rect = pygame.Rect(WIDTH // 2 - 50, TOP_MARGIN, 100, info_height)
    pygame.draw.rect(screen, DARK_GRAY, reset_rect)
    pygame.draw.rect(screen, BLACK, reset_rect, 2)
    reset_text = small_font.render("重置游戏", True, WHITE)
    screen.blit(reset_text, (reset_rect.centerx - reset_text.get_width() // 2,
                             reset_rect.centery - reset_text.get_height() // 2))

    # 绘制网格背景
    grid_bg_rect = pygame.Rect(MARGIN - 10, grid_top - 10,
                               grid_area_width + 20, grid_area_height + 20)
    pygame.draw.rect(screen, (220, 220, 220), grid_bg_rect)
    pygame.draw.rect(screen, DARK_GRAY, grid_bg_rect, 2)

    # 绘制网格
    for x in range(board.width):
        for y in range(board.height):
            rect_x = x * GRID_SIZE + MARGIN
            rect_y = y * GRID_SIZE + grid_top

            cell = board.cells[x][y]

            if cell.is_revealed:
                # 错误标记的格子使用淡红色背景
                if board.game_over and cell.is_flagged and not cell.is_mine:
                    pygame.draw.rect(screen, LIGHT_RED, (rect_x, rect_y, GRID_SIZE, GRID_SIZE))
                else:
                    pygame.draw.rect(screen, WHITE, (rect_x, rect_y, GRID_SIZE, GRID_SIZE))

                if cell.is_mine:
                    # 绘制地雷
                    pygame.draw.circle(screen, BLACK,
                                       (rect_x + GRID_SIZE // 2, rect_y + GRID_SIZE // 2),
                                       GRID_SIZE // 3)
                    # 游戏结束后显示所有地雷位置
                    if board.game_over and not cell.is_flagged:
                        # 未标记的地雷添加红色圆圈
                        pygame.draw.circle(screen, RED,
                                           (rect_x + GRID_SIZE // 2, rect_y + GRID_SIZE // 2),
                                           GRID_SIZE // 4, 2)
                elif cell.neighbor_mines > 0:
                    # 绘制数字
                    text = small_font.render(str(cell.neighbor_mines), True, NUMBER_COLORS[cell.neighbor_mines])
                    screen.blit(text, (rect_x + GRID_SIZE // 2 - text.get_width() // 2,
                                       rect_y + GRID_SIZE // 2 - text.get_height() // 2))
            else:
                # 未揭示的格子
                pygame.draw.rect(screen, GRAY, (rect_x, rect_y, GRID_SIZE, GRID_SIZE))
                if cell.is_flagged:
                    if board.game_over and cell.correctly_flagged:
                        # 游戏结束后正确标记的旗帜用绿色
                        pygame.draw.polygon(screen, GREEN, [
                            (rect_x + 8, rect_y + 8),
                            (rect_x + GRID_SIZE - 8, rect_y + 15),
                            (rect_x + 8, rect_y + GRID_SIZE - 8)
                        ])
                    else:
                        # 正常旗帜
                        pygame.draw.polygon(screen, RED, [
                            (rect_x + 8, rect_y + 8),
                            (rect_x + GRID_SIZE - 8, rect_y + 15),
                            (rect_x + 8, rect_y + GRID_SIZE - 8)
                        ])

            # 绘制格子边框
            pygame.draw.rect(screen, DARK_GRAY, (rect_x, rect_y, GRID_SIZE, GRID_SIZE), 1)

    return grid_top + grid_area_height


def reset_game():
    return Board(GRID_WIDTH, GRID_HEIGHT, MINES)


def main():
    board = reset_game()
    clock = pygame.time.Clock()

    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()

            if event.type == MOUSEBUTTONDOWN:
                mouse_x, mouse_y = event.pos

                # 检查是否点击了重置按钮
                reset_rect = pygame.Rect(WIDTH // 2 - 50, TOP_MARGIN, 100, 40)
                if reset_rect.collidepoint(mouse_x, mouse_y):
                    board = reset_game()
                    continue

                # 检查是否点击在网格内
                grid_top = TOP_MARGIN + 50  # 信息区域高度 + 间距
                grid_bottom = grid_top + GRID_HEIGHT * GRID_SIZE
                if (MARGIN <= mouse_x < MARGIN + GRID_WIDTH * GRID_SIZE and
                        grid_top <= mouse_y < grid_bottom):

                    grid_x = (mouse_x - MARGIN) // GRID_SIZE
                    grid_y = (mouse_y - grid_top) // GRID_SIZE

                    if event.button == 1:  # 左键点击
                        board.reveal(grid_x, grid_y)
                    elif event.button == 3:  # 右键点击
                        board.toggle_flag(grid_x, grid_y)

        # 绘制游戏板
        draw_board(board)
        pygame.display.update()
        clock.tick(30)


if __name__ == "__main__":
    main()